/*
 * This is the in-game representation of a Tile on the map.
 * In contrast to tiles on the layout, map tiles waste space
 * and contain redundant information.
 * Tile behaviors are specified elsewhere since they are
 * part of the game logic, not the world definition.
 */

#ifndef TILE_H_
#define TILE_H_

#include <stdbool.h>
#include "map_object.h"

/*
 * Most Tiles are common tiles, which means they have assigned
 * graphics and basic collision info and no behavior.
 * Changeling tiles are like common tiles, except they may
 * change their basic properties and graphics during the game.
 * Doors are an example.
 * Extended tiles may model all sorts of behavior from stairs
 * and teleporters to special puzzle room tiles.
 */
typedef enum {
	TILE_COMMON,
	TILE_CHANGELING,
	TILE_EXTENDED
} TileType;

typedef enum {
	TE_SPAWN,
	TE_STAIRS,
	TE_TELEPORTER,
	TE_TRIGGER
} TileExtensionType;

typedef struct {
	TileExtensionType type;
	
	// Type specific tile data
	union {
		struct {
			int index; // 0-based sequential unique spawn tile identifier
		} spawn;
		
		struct {
			Direction dir; // DIR_LEVELUP or DIR_LEVELDOWN
			Coord target;
		} stairs;
		
		struct {
			Coord target;
		} teleporter;
		
		/*
		 * NOTE: Doors are unused at the moment.
		 * They may be reintroduced at some time.
		 * 
		struct {
			enum { DOOR_HORIZONTAL, DOOR_VERTICAL } orientation;
			int locks; // if locks <= 0, the door is unlocked/open.
		} door;
		*/
		
		// A trigger's action depends on the type of target and the
		// type of trigger. Combinations are:
		//     - ONCE and door: trigger unlocks the door by 1
		//     - TEMPORARY and door: trigger unlocks the door by 1 
		//                           onmove, locks it by 1 onleave.
		//     - TOGGLE and door: trigger locks the door by 
		//                        trigger_state*2-1
		struct {
			Coord target;
			enum { TRIGGER_ONCE, TRIGGER_TEMPORARY, TRIGGER_TOGGLE } type;
			int state; // 0 by default
		} trigger;
	};	
} TileExtension;

typedef struct {
	TileType type;
	Coord coord;  // location of the tile
	int index;     // index in the map's tile array
	
	// Collision information
	bool blocks_players;  // true if players cannot cross this tile
	bool blocks_monsters; // true if monsters cannot cross this tile
	bool blocks_ghosts;   // collision for entities which are not normally blocked
	bool blocks_objects;  // is it possible to e.g. move a box onto this tile
	
	// Not self-referential references to external information
	bool is_room;      // true if the tile is part of a room
	bool has_actor;    // true if there is an actor occupying the tile
	bool has_object;   // true if there is an object occupying the tile
	int room;          // handle of the room which this tile is part of
	int actor;         // if has_actor, contains handle to the actor on this tile
	MapObject* object; // if has_object, points to the object on this tile
	
	// Graphics data, used by map_display
	int gfx_back[4];   // Handles to absolute background graphics
	int gfx_wallfg[4]; // Optional foreground wall graphics for pseudo 3D
	int n_frames_back; // Number of frames in a tile's background animation
	
	TileExtension* extension; // Most tiles will not have this
} Tile;

void tile_init ();
void tile_cleanup ();

// These functions assign a specific purpose to the tile they are given.
// The following members are left unchanged:
// coords, index, all graphics data
void tile_make_floor (Tile* tile);
void tile_make_wall (Tile* tile);
void tile_make_spawn (Tile* tile, int index);
void tile_make_teleporter (Tile* tile, Coord target);
void tile_make_stairs (Tile* tile, Direction dir, Coord target);

#endif
